home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld: Conference & Expo 2005
/
Macworld Conference and Expo - Documentation CD-ROM (2004).iso
/
mac
/
Adobe Reader 6.0
/
Adobe Reader 6.0.app
/
Contents
/
MacOS
/
JavaScripts
/
debugger.js
< prev
next >
Wrap
Text File
|
2004-01-30
|
19KB
|
685 lines
/*
==========================================================================
Module: debugger.js
==========================================================================
JS functionality for JavaScript Debugger.
==========================================================================
The Software, including this file, is subject to the End User License
Agreement.
Copyright (c) 1998-2002, Adobe Systems Incorporated, All Rights Reserved.
==========================================================================
*/
// The following code "exports" any strings in the list into the current scope.
var msgStrings = new Array(
"IDS_STARTUP_DEBUGGER_MSG",
"IDS_INVALID_BREAKPOINT",
"IDS_EXCEPTION_INLINE",
"IDS_UNABLE_FINDSOURCE",
"IDS_TOP_LEVEL",
"IDS_INVALID_BPLINE",
"IDS_STACK_STRING",
"IDS_CANNOT_EVALWATCH");
for(var n = 0; n < msgStrings.length; n++)
eval(msgStrings[n] + " = " + getString({cPlugInName: "EScript", cStringId: msgStrings[n]}).toSource());
printConsole(IDS_STARTUP_DEBUGGER_MSG+"\n");
/***************************************************************************/
/* Hook functions */
var debugVerbose = false;
var jsStack = null;
var hookType;
var currentFrame;
var resumeCode = 1;
var stepType = -1;
var startPC = 0;
var startLineno = 0;
var startFrame = 0;
var startFileName = "";
var startFunname = "";
var curProps = null;
var curScript = null;
var bpCreate = true;
const TMODE_IGNORE = 0;
const TMODE_TRACE = 1;
const TMODE_BREAK = 2;
const PROTOTYPE = "[[Prototype]]";
const PARENT = "[[Parent]]";
const FOLDER_LEVEL = "Folder-Level";
jsd.SetScriptHook(scriptHook);
jsd.SetExecutionHook(execHook);
function stepNext() {
return (jsStack[0].pc < startPC && jsStack[0].lineno != startLineno || jsStack[0].lineno > startLineno);
}
function shouldStop() {
// In case we've hit an exception.
if (hookType == jsd.JSD_HOOK_THROW) {
var tMode = getThrowMode();
switch (tMode) {
case TMODE_IGNORE:
return false;
break;
case TMODE_TRACE:
case TMODE_BREAK:
var displayString = IDS_EXCEPTION_INLINE.replace('%d', jsStack[0].lineno);
displayString = displayString.replace('%s', jsStack[0].script.funName);
displayString = displayString.replace('%s', jsStack[0].script.fileName);
printConsole(displayString);
return tMode == TMODE_BREAK ? true : false;
break;
default:
return false;
}
}
// if we reach hook due to an interrupt, it's probably a step.
if (hookType == jsd.JSD_HOOK_INTERRUPTED) {
switch (stepType) {
case 0: // Step Byte Code
return true;
break;
case 1: // Step Into
return (jsStack[0].script.fileName != startFileName ||
jsStack[0].script.funName != startFunname) ? true : stepNext();
break;
case 2: // Step Over
return (jsStack.length-1 <= startFrame) ? stepNext() : false;
break;
case 3: // Step Out (of function)
{
if (debugVerbose)
printConsole("condition: "+(jsStack.length-1 < startFrame)+" stepNext: "+stepNext()+"\n");
return (jsStack.length-1 < startFrame) ? stepNext() : false;
}
break;
default: // This in case interrupt button is on, but we're not stepping.
return true;
break;
}
}
// make sure we're not stepping.
if (stepType == -1) {
// if we reach hook due to a breakpoint, it's a breakpoint.
if (hookType == jsd.JSD_HOOK_BREAKPOINT) {
var bpIndex = getBPIndex(jsStack[0].script.fileName, jsStack[0].lineno);
if (bpIndex != -1) {
var ret = debugEval(breakpoints[bpIndex].condition);
if (debugVerbose)
printConsole(breakpoints[bpIndex].condition+": "+ ret +"\n");
if (ret == "true") {
if (debugVerbose)
printConsole(typeof(ret) + ": Ok\n");
return true;
}
}
}
// if we reach hook due to "debugger keyword", it's a breakpoint.
if (hookType == jsd.JSD_HOOK_DEBUGGER_KEYWORD)
return true;
}
// No, we're not going to stop.
return false;
}
function GetTextFromFilename(filename) {
var handle = jsd.FindSourceForURL(filename);
if (handle == null)
return printConsole(IDS_UNABLE_FINDSOURCE.replace('%s', filename));
return jsd.GetSourceText(handle);
}
function execHook(type) {
/* we reset these globals. hookType is reason for stoping. */
jsStack = null;
currentFrame = 0;
hookType = type;
buildStack();
if (debugVerbose) {
printConsole("hookType: "+hookType+" stepType: "+stepType+"\n");
printConsole("lineno: "+jsStack[0].lineno+" fileName: "+jsStack[0].script.fileName+"\n");
}
if (shouldStop()) {
openDebugger();
unsuspend();
// reset these.
resumeCode = -1;
stepType = -1;
selectScriptLine(jsStack[0].lineno, jsStack[0].script.fileName, "", 0);
suspendThread();
if (debugVerbose)
printConsole("resumeCode: "+resumeCode+"\n");
return resumeCode;
}
return jsd.JSD_HOOK_RETURN_CONTINUE;
}
function scriptHook(handle, creating) {
if (creating) {
JSDScript.add(new JSDScript(handle,
jsd.GetScriptFilename(handle),
jsd.GetScriptFunctionName(handle),
jsd.GetScriptBaseLineNumber(handle),
jsd.GetScriptLineExtent(handle)));
setAllBreakpointsForScript(handle);
} else {
JSDScript.remove(JSDScript.find(handle));
}
return true;
}
/***************************************************************************/
/* JSDScript Object */
function JSDScript(handle, fileName, funName, base, extent) {
this.handle = handle;
this.fileName = fileName;
this.funName = (funName != null && funName.length ? funName : IDS_TOP_LEVEL);
this.base = base;
this.extent = extent;
this.toString = function() {return (funName != null && funName.length ? funName : IDS_TOP_LEVEL)}
if (debugVerbose)
printConsole(fileName + ":" + base + ":" + extent +"\n");
}
JSDScript.scripts = new Object;
JSDScript.add = function(script) {
JSDScript.scripts[script.handle] = script;
addPCMap(script);
/* use this to see the final pcMap on the console
if (script.toString() == "top_level" && script.fileName == "Folder-Level:App:aform.js")
{
var filePCMap = findPCMap(script);
for (var i = 0; i < Math.min(150, filePCMap.exec.length); i++)
printConsole(i + ":" + filePCMap.exec[i] +"\n");
}
*/
}
JSDScript.remove = function(script) {
if (script) {
if (debugVerbose)
printConsole(script.fileName + ":" + script.funName +"\n");
delete JSDScript.scripts[script.handle];
if (script.fileName.substr(0, FOLDER_LEVEL.length) != FOLDER_LEVEL)
deletePCMap(script);
}
}
JSDScript.find = function(handle) {
return JSDScript.scripts[handle];
}
/***************************************************************************/
/* PCMaps Array */
var scriptPCMaps = new Array;
function filePCMap(fileName) {
this.fileName = fileName;
this.exec = new Array();
}
function findPCMapFromFilename(fileName) {
for(var i = 0; i < scriptPCMaps.length; i++) {
if (scriptPCMaps[i].fileName == fileName)
return scriptPCMaps[i];
}
return null;
}
function findPCMap(script) {
var pcMap = findPCMapFromFilename(script.fileName);
if (!pcMap) {
pcMap = new filePCMap(script.fileName);
scriptPCMaps.push(pcMap);
}
return pcMap;
}
function addPCMap(script) {
var filePCMap = findPCMap(script);
for(var i = script.base; i < script.base+script.extent; i++) {
var line = jsd.GetClosestLine(script.handle, jsd.GetClosestPC(script.handle, i));
filePCMap.exec[i] = filePCMap.exec[i] || (i == line) ? true : false;
if (debugVerbose)
printConsole(i + ":" + filePCMap.exec[i] +"\n");
}
}
function deletePCMap(script) {
for(var i = 0; i < scriptPCMaps.length; i++) {
if (scriptPCMaps[i].fileName == script.fileName) {
delete scriptPCMaps[i];
scriptPCMaps.splice(i, 1);
return;
}
}
}
function canSetBreakpoint(fileName, lineNum) {
var pcMap = findPCMapFromFilename(fileName);
if (pcMap != undefined)
return pcMap.exec[lineNum];
return true;
}
function pcMapExists(fileName) {
if (findPCMapFromFilename(fileName))
return true;
return false;
}
/***************************************************************************/
/* JSDFrame (jsStack) Object */
function JSDFrame(handle) {
this.handle = handle;
this.script = JSDScript.find(jsd.GetScriptForStackFrame(handle));
this.pc = jsd.GetPCForStackFrame(handle);
this.lineno = jsd.GetClosestLine(this.script.handle, this.pc);
}
function buildStack() {
var count = jsd.GetCountOfStackFrames();
jsStack = new Array(count);
jsStack[0] = new JSDFrame(jsd.GetStackFrame());
for(var i = 0; i < count-1; i++)
jsStack[i+1] = new JSDFrame(jsd.GetCallingStackFrame(jsStack[i].handle));
}
/***************************************************************************/
/* JSDProperty Object */
function JSDProperty(propValue, readOnly) {
this.value = propValue;
this.type = (jsd.IsValueObject(propValue) ? "o" : "") +
(jsd.IsValueInt(propValue) ? "i" : "") +
(jsd.IsValueDouble(propValue) ? "d" : "") +
(jsd.IsValueString(propValue) ? "s" : "") +
(jsd.IsValueBoolean(propValue) ? "b" : "") +
(jsd.IsValueVoid(propValue) ? "u" : "") +
(readOnly ? "r" : "w");
this.valString = jsd.GetValueString(propValue);
// this.count = jsd.GetCountOfProperties(propValue);
}
/***************************************************************************/
/* JSDValue Object */
function JSDValue(handle) {
if (!handle)
return null;
this.handle = handle;
this.a = new Array();
this.GetPropNames = function() {return this.a;}
this.GetProperties = function() {
var o = new Object();
jsd.IterateProperties(this.handle, cb, o, this.a);
if (jsd.GetValueClassName(this.handle) != "Array")
this.a.sort();
var protoValue = jsd.GetValuePrototype(this.handle);
if (protoValue) {
o[PROTOTYPE] = new JSDProperty(protoValue, true);
this.a.unshift(PROTOTYPE);
}
var parentValue = jsd.GetValueParent(this.handle);
if (parentValue) {
o[PARENT] = new JSDProperty(parentValue, true);
this.a.unshift(PARENT);
}
return o;
}
function cb(ob, prop, o, a) {
var propValue = jsd.GetPropertyValue(prop);
if (!jsd.IsValueFunction(propValue)) {
var propName = jsd.GetValueString(jsd.GetPropertyName(prop));
if (propName != "__privateErase") {
o[propName] = new JSDProperty(propValue, (jsd.GetPropertyFlags(prop) & jsd.JSDPD_READONLY));
a.push(propName);
// if (debugVerbose)
// printConsole(propName+":"+jsd.GetValueString(propValue)+"\n");
}
}
return true;
}
}
/***************************************************************************/
/* Breakpoints */
breakpoints = new Array();
function enumBreakpoints() {
for(var i = 0; i < breakpoints.length; i++)
regBreakpoint(i, breakpoints[i].fileName, breakpoints[i].lineNum, breakpoints[i].condition);
}
function setBreakpoints(pddHandle, bpArray) {
for(var i = 0; i < bpArray.length; i++) {
var fileName = bpArray[i].fileName;
if (fileName.substr(fileName.length - 3) != ".js")
setBreakpoint(pddHandle, fileName, bpArray[i].lineNum, bpArray[i].condition);
}
}
function Breakpoint(pddHandle, fileName, lineNum, condition) {
this.pddHandle = pddHandle;
this.fileName = fileName;
this.lineNum = lineNum;
this.condition = condition;
this.isSet = false;
}
function getBPIndex(fileName, lineNum) {
for(var i = 0; i < breakpoints.length; i++)
if (breakpoints[i].fileName == fileName && breakpoints[i].lineNum == lineNum)
return i;
return -1;
}
function bpCallback(handle, fileName, lineno, set) {
var script = JSDScript.find(handle);
if (script && script.fileName == fileName) {
if (script.base <= lineno && script.base+script.extent > lineno)
{
var pc = jsd.GetClosestPC(handle, lineno);
if (lineno == jsd.GetClosestLine(handle, pc)) {
set ? jsd.SetTrap(handle, pc) : jsd.ClearTrap(handle, pc);
bpCreate = true;
// printConsole((set ? "set" : "clear") + fileName +"\n");
return false; // if iterating, stop, as we found bp.
}
} else {
bpCreate = false;
}
}
return true;
}
function setAllBreakpointsForScript(handle) {
for(var i = 0; i < breakpoints.length; i++) {
bpCreate = false;
bpCallback(handle, breakpoints[i].fileName, breakpoints[i].lineNum, true);
if (bpCreate)
breakpoints[i].isSet = true;
}
var script = JSDScript.find(handle);
if (script.funName == "") {
for(var i = 0; i < breakpoints.length; i++) {
if (breakpoints[i].fileName == script.fileName && !breakpoints[i].isSet) {
var displayString = IDS_INVALID_BPLINE.replace('%d', breakpoints[i].lineNum);
displayString = displayString.replace('%s', breakpoints[i].fileName);
printConsole(displayString);
updateBreakpoint(false, breakpoints[i].lineNum, i, breakpoints[i].fileName, breakpoints[i].condition);
delete breakpoints[i];
breakpoints.splice(i, 1);
i--;
}
}
}
}
function setBreakpoint(pddHandle, fileName, lineNum, condition) {
bpCreate = canSetBreakpoint(fileName, lineNum);
if (bpCreate) {
var bpIndex = getBPIndex(fileName, lineNum);
if (bpIndex == -1) {
jsd.IterateScripts(bpCallback, fileName, lineNum, true);
var theCondition = (condition == undefined) ? "true" : condition;
breakpoints[breakpoints.length] = new Breakpoint(pddHandle, fileName, lineNum, theCondition);
updateBreakpoint(true, lineNum, breakpoints.length-1, fileName, theCondition);
saveBreakpoints();
}
if (debugVerbose)
printConsole("breakpoint set at line "+pddHandle+" of "+fileName+"\n");
} else {
var displayString = IDS_INVALID_BREAKPOINT.replace('%d', lineNum);
displayString = displayString.replace('%s', fileName);
displayAlert(displayString);
}
}
function clearBreakpoint(fileName, lineNum) {
var bpIndex = getBPIndex(fileName, lineNum);
if (bpIndex != -1) {
jsd.IterateScripts(bpCallback, fileName, lineNum, false);
delete breakpoints[bpIndex];
breakpoints.splice(bpIndex, 1);
updateBreakpoint(false, lineNum, bpIndex, fileName, "");
saveBreakpoints();
}
if (debugVerbose)
printConsole("breakpoint cleared at line "+lineNum+" of "+fileName+"\n");
}
function clearBreakpointsForDoc(pddHandle) {
for(var i = 0; i < breakpoints.length; i++) {
if (breakpoints[i].pddHandle == pddHandle) {
updateBreakpoint(false, breakpoints[i].lineNum, i, breakpoints[i].fileName, breakpoints[i].condition);
delete breakpoints[i];
breakpoints.splice(i, 1);
i--;
}
}
}
function toggleBreakpoint(pddHandle, fileName, lineNum, condition) {
var bpIndex = getBPIndex(fileName, lineNum);
if (bpIndex == -1)
setBreakpoint(pddHandle, fileName, lineNum, condition);
else
clearBreakpoint(fileName, lineNum);
}
function updateBreakpointsForScript(fileName) {
for(var i = 0; i < breakpoints.length; i++) {
if (breakpoints[i].fileName == fileName)
updateBreakpoint(true, breakpoints[i].lineNum, i, fileName, breakpoints[i].condition);
}
}
function changeBPCondition(i, newCondition) {
if (i >= 0 && i < breakpoints.length && newCondition) {
breakpoints[i].condition = newCondition;
updateBreakpoint(true, breakpoints[i].lineNum, i, breakpoints[i].fileName, breakpoints[i].condition);
saveBreakpoints();
}
}
/***************************************************************************/
/* JSDebugger dialog uses this API. */
function unsuspend() {
if (jsd.InterruptSet) {
jsd.ClearInterrupt();
updateStopIcon();
}
}
function suspend() {
if (!jsd.InterruptSet) {
jsd.SendInterrupt();
updateStopIcon();
}
}
function isInterruptSet() {
return jsd.InterruptSet;
}
function step(type) {
if (jsStack) {
stepType = type;
/* frame for step is always 0. */
startPC = jsStack[0].pc;
startLineno = jsStack[0].lineno;
startFileName = jsStack[0].script.fileName;
startFunname = jsStack[0].script.funName;
startFrame = jsStack.length-1;
suspend();
resume();
}
}
function quit() {
clearStack();
clearInspector();
curProps = null;
curScript = null;
unsuspend();
stepType = -1;
resume(jsd.JSD_HOOK_RETURN_HOOK_ERROR);
}
function resume(code) {
if (arguments.length &&
code >= jsd.JSD_HOOK_RETURN_HOOK_ERROR &&
code <= jsd.JSD_HOOK_RETURN_CONTINUE_THROW) {
resumeCode = code;
} else {
if (hookType == jsd.JSD_HOOK_THROW)
resumeCode = jsd.JSD_HOOK_RETURN_CONTINUE_THROW;
else
resumeCode = jsd.JSD_HOOK_RETURN_CONTINUE;
}
}
function listRecursive(bThis) {
if (jsStack) {
if (jsStack[currentFrame].script.toString() != curScript)
clearInspector();
var callObjHandle = bThis ? jsd.GetThisForStackFrame(jsStack[currentFrame].handle) :
jsd.GetScopeChainForStackFrame(jsStack[currentFrame].handle);
displayRecursive(false, callObjHandle);
curScript = jsStack[currentFrame].script.toString();
}
}
function displayRecursive(isNode, callObjHandle) {
if (callObjHandle) {
var callObj = new JSDValue(callObjHandle);
if (callObj) {
var props = callObj.GetProperties();
if (props) {
var namesArray = callObj.GetPropNames();
for(var i = 0; i < namesArray.length; i++) {
var name = namesArray[i];
var isExpanded = printInspector(isNode, i, props[name].type, name, props[name].valString);
if (isExpanded && props[name].type[0] == "o") {
displayRecursive(true, props[name].value);
if (debugVerbose)
printConsole(name+":"+props[name].valString+"\n");
}
isNode = false;
}
getParentList();
}
}
}
}
function where() {
if (jsStack) {
for(var i = 0; i < jsStack.length; i++) {
var displayString = IDS_STACK_STRING.replace('%d', jsStack[i].lineno);
displayString = displayString.replace('%s', jsStack[i].script.toString());
printStack(displayString);
}
}
}
function selectFrame(frameNum) {
currentFrame = frameNum;
selectScriptLine(jsStack[currentFrame].lineno, jsStack[currentFrame].script.fileName, "", frameNum);
}
function debugEval(text) {
var scopeChain = jsd.GetScopeChainForStackFrame(jsStack[currentFrame].handle);
var ret;
try {
ret = jsd.EvaluateScriptInStackFrame.apply(scopeChain, [jsStack[currentFrame].handle, text]);
} catch (e) {
return e;
}
return ret;
}
function watch(i, text) {
if (jsStack && text != "") {
var ret = debugEval(text);
printWatch(i, text, ret.toString());
} else {
printWatch(i, text, IDS_CANNOT_EVALWATCH);
}
}
function changeLocal(varName, value, bThis) {
if (jsStack) {
var ret = debugEval(varName + " = " + value + ";");
listRecursive(bThis);
}
}
function scriptExists(fileName) {
for(var i in JSDScript.scripts) {
if (fileName == JSDScript.scripts[i].fileName)
return true;
}
return false;
}
function listScriptFunctions(fileName) {
var o = new Object();
for(var i in JSDScript.scripts) {
var script = JSDScript.scripts[i];
if (script && fileName == script.fileName)
o[script.funName] = script.base;
}
for(var i in o)
printFunction(i, o[i]);
}